package com.dhcc.bpm.modules.common.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dhcc.bpm.common.annotation.Log;
import com.dhcc.bpm.common.constant.FilePathConstant;
import com.dhcc.bpm.common.enums.BusinessType;
import com.dhcc.bpm.common.utils.StringUtils;
import com.dhcc.bpm.common.utils.YamlUtils;
import com.dhcc.bpm.modules.api.entity.BaseProduct;
import com.dhcc.bpm.modules.api.entity.Sys;
import com.dhcc.bpm.modules.api.service.IApiService;
import com.dhcc.bpm.modules.api.service.IBaseProductService;
import com.dhcc.bpm.modules.api.service.ISysService;
import com.dhcc.bpm.modules.common.entity.OpenApi;
import com.dhcc.bpm.modules.common.entity.Plupload;
import com.dhcc.bpm.modules.common.entity.Upload;
import com.dhcc.bpm.modules.common.service.IPluploadService;
import com.dhcc.bpm.modules.common.service.WordService;
import com.dhcc.bpm.modules.common.vo.PluploadVO;
import com.dhcc.bpm.modules.system.entity.Dict;
import com.dhcc.bpm.modules.system.entity.Param;
import com.dhcc.bpm.modules.system.service.IDictService;
import com.dhcc.bpm.modules.system.service.impl.ParamServiceImpl;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.commons.io.FileUtils;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;
import org.yaml.snakeyaml.Yaml;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import javax.validation.Valid;
import java.io.*;
import java.util.*;

/**
 * @ClassName DocDirectoryController
 * @Description 公共模块表 控制器
 * @Author xiafayu
 * @Date 2020/2/21 14:16
 * @Version V1.0
 * @Copyright: 2020 东华软件 . All rights reserved.
 */
@RestController
@AllArgsConstructor
@NoArgsConstructor
@RequestMapping("bpm-common/plupload")
@Api(value = "公共模块表", tags = "公共模块表接口")
public class PluploadController extends BladeController {
    private static final Logger log = LoggerFactory.getLogger(PluploadController.class);
    @Value("${bpm.file-type}")
    private String supportFileType;
    private String openApiPath;
    private String publicPath;
    @Value("${bpm.file-public-path}")
    public void setFileUploadPath(String publicPath) {
        openApiPath = publicPath + FilePathConstant.OPENAPIPATH;
        this.publicPath = publicPath;
    }

    private List<String> supportWordType = Lists.newArrayList("doc", "docx", "md", "xls", "xlsx");
    private List<String> supportApiType = Lists.newArrayList("json", "yml", "yaml");
    private List<String> supportPhotoType = Lists.newArrayList("jpg", "png");
    @Autowired
    private IPluploadService pluploadService;
    @Autowired
    private ParamServiceImpl paramService;
    @Autowired
    private IBaseProductService baseProductService;
    @Autowired
    private ISysService sysService;
    @Autowired
    IApiService apiService;
    @Autowired
    IDictService dictService;
    @Autowired
    WordService wordService;
    @Autowired
    private SpringTemplateEngine springTemplateEngine;

    /**
     * @param plupload
     * @return org.springblade.core.tool.api.R<com.dhcc.bpm.modules.common.entity.Plupload>
     * @throws
     * @Description 详情
     * @Author xiafayu
     * @Date 2020/3/3 8:44
     **/
    @ApiLog("公共模块表详情")
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "详情", notes = "传入plupload")
    public R<Plupload> detail(Plupload plupload) {
        Plupload detail = pluploadService.getOne(Condition.getQueryWrapper(plupload));
        return R.data(detail);
    }

    /**
     * @param plupload
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.common.entity.Plupload>>
     * @throws
     * @Description 分页 公共模块表
     * @Author xiafayu
     * @Date 2020/3/3 8:44
     **/
    @ApiLog("公共模块表分页")
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "分页", notes = "传入plupload")
    public R<IPage<Plupload>> list(Plupload plupload, Query query) {
        IPage<Plupload> pages = pluploadService.page(Condition.getPage(query), Condition.getQueryWrapper(plupload));
        return R.data(pages);
    }

    @ApiLog("xml文件读取")
    @GetMapping("/xmlRead")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "xml文件读取", notes = "传入Id")
    public R<String> xmlRead(Long id) throws IOException {
        Plupload plupload = new Plupload();
        plupload.setId(id);
        Plupload detail = pluploadService.getOne(Condition.getQueryWrapper(plupload));
        if (detail == null) {
            return R.fail("数据不存在");
        }
        String fullPath = detail.getFileFullpath();
        if (StringUtils.isEmpty(fullPath)) {
            return R.fail("文件路径不正确");
        }
        log.info("配置文件路径：{}", fullPath);
//		File file  = new File(fullPath.replace("/file", pluploadProxy));
        File file = new File(fullPath.replace("/file", publicPath));
        if (file.exists()) {
            if (fullPath.endsWith(".doc") || fullPath.endsWith(".docx")) {
//				InputStream is = new FileInputStream(fullPath.replace("/file", pluploadProxy));
                InputStream is = new FileInputStream(fullPath.replace("/file", publicPath));
                XWPFDocument doc = new XWPFDocument(is);
                XWPFWordExtractor extractor = new XWPFWordExtractor(doc);
                return R.data(extractor.getText());
            } else {
                return R.data(FileUtils.readFileToString(file, "utf-8"));
            }
        } else {
            return R.data("");
        }

    }

    @ApiLog("xml文件写入")
    @PostMapping("/xmlSave")
    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "xml文件读取", notes = "传入Id")
    public R<String> xmlWrite(Long id, String xml) throws IOException {
        log.info("xml:{}", xml);
        Plupload plupload = new Plupload();
        plupload.setId(id);
        Plupload detail = pluploadService.getOne(Condition.getQueryWrapper(plupload));
        if (detail == null) {
            return R.fail("数据不存在");
        }
        String fullPath = detail.getFileFullpath();
        if (StringUtils.isEmpty(fullPath)) {
            return R.fail("文件路径不正确");
        }
//		File file  = new File(pluploadProxy+fullPath.substring(5));
        File file = new File(fullPath);
//		File file  = new File(fullPath);

        if (file.exists()) {
            file.getParentFile().mkdirs();
            Base64.Decoder decoder = Base64.getDecoder();
            xml = new String(decoder.decode(xml), "UTF-8");
            FileUtils.writeStringToFile(file, xml, false);
            return R.data("ok");
        } else {
            return R.data("fail");
        }

    }


    /**
     * @param plupload
     * @param query
     * @return org.springblade.core.tool.api.R<com.baomidou.mybatisplus.core.metadata.IPage < com.dhcc.bpm.modules.common.vo.PluploadVO>>
     * @throws
     * @Description 自定义分页
     * @Author xiafayu
     * @Date 2020/3/3 8:45
     **/
    @ApiLog("公共模块表分页")
    @GetMapping("/page")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "分页", notes = "传入plupload")
    public R<IPage<PluploadVO>> page(PluploadVO plupload, Query query) {
        IPage<PluploadVO> pages = pluploadService.selectPluploadPage(Condition.getPage(query), plupload);
        return R.data(pages);
    }

    /**
     * @param plupload
     * @return org.springblade.core.tool.api.R
     * @throws
     * @Description 新增
     * @Author xiafayu
     * @Date 2020/3/3 8:45
     **/
    @ApiLog("公共模块表新增")
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "新增", notes = "传入plupload")
    @Log(title = "文件", businessType = BusinessType.INSERT)
    public R save(@Valid @RequestBody Plupload plupload) {
        return R.status(pluploadService.save(plupload));
    }

    /**
     * @param plupload
     * @return org.springblade.core.tool.api.R
     * @throws
     * @Description 修改
     * @Author xiafayu
     * @Date 2020/3/3 8:45
     **/
    @ApiLog("公共模块表修改")
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "修改", notes = "传入plupload")
    @Log(title = "文件", businessType = BusinessType.UPDATE)
    public R update(@Valid @RequestBody Plupload plupload) {
        return R.status(pluploadService.updateById(plupload));
    }

    /**
     * @param plupload
     * @return org.springblade.core.tool.api.R
     * @throws
     * @Description 新增或修改
     * @Author xiafayu
     * @Date 2020/3/3 8:46
     **/
    @ApiLog("公共模块表新增修改")
    @PostMapping("/submit")
    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "新增或修改", notes = "传入plupload")
    @Log(title = "文件", businessType = BusinessType.INSERT)
    public R submit(@Valid @RequestBody Plupload plupload) {
        return R.status(pluploadService.saveOrUpdate(plupload));
    }


    /**
     * @param ids
     * @return org.springblade.core.tool.api.R
     * @throws
     * @Description 删除
     * @Author xiafayu
     * @Date 2020/3/3 8:46
     **/
    @ApiLog("公共模块表删除")
    @PostMapping("/remove")
    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "逻辑删除", notes = "传入ids")
    @Log(title = "文件", businessType = BusinessType.DELETE)
    public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
        return R.status(pluploadService.deleteLogic(Func.toLongList(ids)));
    }

    /**
     * @author: ChenZe
     * @date: 2019/11/29 15:04
     * @description: 文件上传
     * @param: [plupload, request]
     * @return: org.springblade.core.tool.api.R
     */
    @ApiLog("文件上传")
    @PostMapping("/fileUpload")
    @Log(title = "文件上传", businessType = BusinessType.UPLOAD)
    public R uploadFile(PluploadVO plupload, HttpServletRequest request) {
        //获取请求信息的文件名称
        String name = null;
        Upload upload = new Upload();
        upload.setRequest(request);
        upload.setApiName(request.getParameter("apiCode"));
        Upload uploadEntity = pluploadService.getFile(upload);
        MultipartFile file = uploadEntity.getMultipartFile();
        name = file.getOriginalFilename();
        uploadEntity.setName(name);
        String fileType = name.substring(name.lastIndexOf(".") + 1);
        //限制上传文件类型
        if (!supportFileType.contains(fileType)) {
            return R.fail("请上传正确的文件!");
        }
        //本地上传
        String id = pluploadService.fileLocalUpload(plupload, upload, request).toString();
//		String id = pluploadService.fileUpload(plupload, upload, request).toString();
        if ("".equals(id) || id == null) {
            return R.status(false);
        } else {
            return R.data(id);
        }
    }

    /**
     * @author: ChenZe
     * @date: 2019/11/29 16:54
     * @description: 文件下载
     * @param: [id, request, response]
     * @return: org.springblade.core.tool.api.R
     */
    @ApiLog("文件下载")
    @GetMapping("/fileDownload")
    @Log(title = "文件下载", businessType = BusinessType.DOWNLOAD)
    public R downloadFile(@RequestParam Long id, HttpServletRequest request, HttpServletResponse response) {
        pluploadService.fileDownload(id, request, response);
        return R.status(true);
    }

    /**
     * @author: 陈泽
     * @date: 2019/12/9 9:42
     * @description: 文件删除
     * @param: [id]
     * @return: org.springblade.core.tool.api.R
     */
    @ApiLog("文件删除")
    @PostMapping("/fileDelete")
    @Log(title = "文件删除", businessType = BusinessType.DELETE)
    public R deleteFile(Long id) {
        return R.status(pluploadService.fileDelete(id));
    }

    /**
     * 文档word上传
     *
     * @param plupload
     * @param request
     * @return
     */
    @ApiLog("文档word上传")
    @PostMapping("/fileDocUpload")
    @Log(title = "文档word上传", businessType = BusinessType.UPLOAD)
    public R fileDocUpload(Plupload plupload, HttpServletRequest request, String apiVersion, String opcSysId, String productNum, String backserviceId, String apiNum) {
        if (backserviceId != null && !"".equals(backserviceId)) {
            List<BaseProduct> baseProducts = baseProductService.selectById(Long.parseLong(backserviceId));
            if (baseProducts != null && baseProducts.size() > 0) {
                opcSysId = baseProducts.get(0).getOpcSysId().toString();
                productNum = baseProducts.get(0).getProductNum();
            }
        }
        if (opcSysId != null && !"".equals(opcSysId)) {
            Sys sys = new Sys();
            sys.setId(Long.parseLong(opcSysId));
            Sys one = sysService.getOne(Condition.getQueryWrapper(sys));
            if (one != null) {
                opcSysId = one.getSysNum();
            }
        }
        String name = null;
        Upload upload = new Upload();
        upload.setRequest(request);
        upload.setApiName(apiNum);
        Upload uploadEntity = pluploadService.getFile(upload);
        MultipartFile file = uploadEntity.getMultipartFile();
        name = file.getOriginalFilename();
        uploadEntity.setName(name);
        String fileType = name.substring(name.lastIndexOf(".") + 1);
        //限制上传文件类型 doc/docx
        if (!supportWordType.contains(fileType)) {
            return R.fail("请上传word或markdown类型文档！");
        }
        Param param = paramService.getParamByKey("bpm.docLocalUpload");
        String paramValue = param.getParamValue();
        plupload.setStorageType(Long.valueOf(paramValue));
        String id = "";
        if (backserviceId != null) {
            id = pluploadService.fileUpload(plupload, upload, opcSysId, productNum, apiNum, apiVersion, request).toString();
        } else if (opcSysId != null && productNum != null) {
            id = pluploadService.fileUpload(plupload, upload, opcSysId, productNum, request).toString();
        } else {
            id = pluploadService.fileUpload(plupload, upload, request).toString();
        }
        if ("".equals(id) || id == null) {
            return R.status(false);
        } else {
            return R.data(id);
        }
    }

    /**
     * @param plupload
     * @param request
     * @return org.springblade.core.tool.api.R
     * @throws
     * @Description 上传头像
     * @Author xiafayu
     * @Date 2020/3/3 8:46
     **/
    @ApiLog("上传头像")
    @PostMapping("/photoUpload")
    @Log(title = "上传头像", businessType = BusinessType.UPLOAD)
    public R photoUpload(Plupload plupload, HttpServletRequest request) {
        //请求信息
        String name = null;
        Upload upload = new Upload();
        upload.setRequest(request);
        Upload uploadEntity = pluploadService.getFile(upload);
        MultipartFile file = uploadEntity.getMultipartFile();
        name = file.getOriginalFilename();
        uploadEntity.setName(name);
        String fileType = name.substring(name.lastIndexOf(".") + 1);
        //限制上传文件类型
        if (!supportPhotoType.contains(fileType)) {
            return R.fail("请上传图片!");
        }
        String path = pluploadService.photoUpload(plupload, upload, request).toString();
        if ("".equals(path) || path == null) {
            return R.status(false);
        } else {
            return R.data(path);
        }
    }

    /**
     * openApi3.0文档上传
     *
     * @param plupload
     * @param request
     * @return
     */
    @ApiLog("openApi3.0文档上传")
    @PostMapping("/fileApiDocUpload")
    @Log(title = "openApi3.0文档上传", businessType = BusinessType.UPLOAD)
    public R fileApiDocUpload(Plupload plupload, HttpServletRequest request) throws IOException, ServletException {
        Collection<Part> parts = request.getParts();
        Gson gs = new Gson();
        String message = "";
        String docName = "";
        for (Iterator<Part> iterator = parts.iterator(); iterator.hasNext(); ) {
            Part part = iterator.next();
            InputStream in = part.getInputStream();
            docName = part.getSubmittedFileName();
            if (part.getSubmittedFileName().endsWith(".yml") || part.getSubmittedFileName().endsWith(".yaml")) {
                Yaml yaml = new Yaml();
                Map<String, Object> map = (Map<String, Object>) yaml.load(in);
                message = new JSONObject(map).toJSONString();
            } else {
                BufferedReader br = new BufferedReader(new InputStreamReader(in));
                String line;
                StringBuilder sb = new StringBuilder();
                while ((line = br.readLine()) != null) {
                    message += line;
                }
            }
            log.info("文件内容：{}", message);
        }
        Context context = new Context();
        context.setVariables(wordService.tableListFromString(message));
        String content = springTemplateEngine.process("word", context);
        pluploadService.htmlToWord(content, docName);

        String name = null;
        Upload upload = new Upload();
        upload.setRequest(request);
        Upload uploadEntity = pluploadService.getFile(upload);
        MultipartFile file = uploadEntity.getMultipartFile();
        name = file.getOriginalFilename();
        uploadEntity.setName(name);
        String fileType = name.substring(name.lastIndexOf(".") + 1);
        //限制上传文件类型 yml/json/yaml
        if (!supportApiType.contains(fileType)) {
            return R.fail("请上传opeanApi3.0类型文档！");
        }
        Param param = paramService.getParamByKey("bpm.docLocalUpload");
        String paramValue = param.getParamValue();
        plupload.setStorageType(Long.valueOf(paramValue));
        String id = pluploadService.fileUpload(plupload, upload, request).toString();
        if ("".equals(id) || id == null) {
            return R.status(false);
        } else {
            JSONObject json = JSONObject.parseObject(message);
            JSONObject info = json.getJSONObject("info");
            JSONObject paths = json.getJSONObject("paths");
            JSONObject components = json.getJSONObject("components");
            if (info == null || paths == null || components == null) {
                return R.fail("该文件内容格式不符合标准，请重新上传！");
            }
            com.dhcc.bpm.modules.api.entity.Api api = new com.dhcc.bpm.modules.api.entity.Api();
            api.setApiName(info.getString("title"));
            api.setApiVersion(info.getString("version"));
            api.setDescribe(info.getString("description"));
            api.setApiPath(keyName(paths));
            if (keyName(paths) != null && paths.getJSONObject(keyName(paths)) != null) {
                String type = keyName(paths.getJSONObject(keyName(paths)));
                List<Dict> tree = dictService.getList("access_method");
                tree.forEach(dict -> {
                    if (dict.getDictValue().equalsIgnoreCase(type)) {
                        api.setRequestMethod(Integer.valueOf(dict.getDictKey()));
                    }
                });
            }
            api.setIsUpgrade("1");
            api.setIsRecommend("1");
            api.setBusId(Long.valueOf(id));
            api.setIsStandardApi("1");
            apiService.saveOrUpdate(api);
            return R.data(api);
        }
    }

    public String keyName(JSONObject json) {
        String keyName = "";
        Iterator<String> keys = json.keySet().iterator();
        while (keys.hasNext()) {
            keyName = keys.next();
        }
        return keyName;
    }

    /**
     * @param data
     * @param request
     * @return
     */
    @PostMapping("/openApiUpload")
    public R openApiUpload(@RequestBody OpenApi data, HttpServletRequest request) throws UnsupportedEncodingException {
        String apiId = data.getApiId();
        String type = data.getType();
        String info = data.getInfo();
        Base64.Decoder decoder = Base64.getDecoder();
        info = new String(decoder.decode(info), "UTF-8");
//		info = info.replaceAll("↵","\n");
        com.dhcc.bpm.modules.api.entity.Api api = apiService.getById(Long.valueOf(apiId));
        //yml文件保存路径
        File path = new File(openApiPath + "/" + api.getApiCode() + "/");
        if (!path.exists()) {
            path.mkdirs();
        }
        File file = new File(openApiPath + "/" + api.getApiCode() + "/openApi3.yaml");
        try (PrintStream ps = new PrintStream(new FileOutputStream(file))) {
            ps.println(info);
        } catch (FileNotFoundException e) {
            log.error("异常信息：{}", e);
            return R.status(false);
        }
        if (type.equals("json")) {
            //要求的是json格式
            String jsonStr = YamlUtils.yamlToJson(file.getAbsolutePath());
            api.setOpenapiPath(openApiPath + "/" + api.getApiCode() + "/api.json");
            File jsonFile = new File(openApiPath + "/" + api.getApiCode() + "/api.json");
            try (PrintStream ps = new PrintStream(new FileOutputStream(jsonFile))) {
                ps.println(jsonStr);
            } catch (FileNotFoundException e) {
                log.error("异常信息：{}", e);
                return R.status(false);
            }
        } else {
            //要求的是yaml格式
            api.setOpenapiPath(openApiPath + "/" + apiId + "/openApi3.yaml");
        }
        apiService.updateById(api);
        return R.status(true);
    }

    /**
     * @return
     */
    @GetMapping("/openApi/{apiId}")
    public R<String> openApiUpload(@PathVariable("apiId") String apiId) {
        com.dhcc.bpm.modules.api.entity.Api api = apiService.getById(Long.valueOf(apiId));
        if (null == api) {
            return R.data(null);
        }
        if (api.getOpenapiPath() == null || "".equals(api.getOpenapiPath())) {
            return R.data(null);
        }
        String filePath = api.getOpenapiPath();
        Param param = paramService.getParamByKey("bpm.fileUploadType");
        String paramValue = param.getParamValue();
        String str = "";
        if ("1".equals(paramValue)) {
            File file = new File(filePath);
            try (FileInputStream in = new FileInputStream(file)) {
                // size  为字串的长度 ，这里一次性读完
                int size = in.available();
                byte[] buffer = new byte[size];
                in.read(buffer);
                in.close();
                str = new String(buffer, "UTF-8");
            } catch (IOException e) {
                log.error("异常信息：{}", e);
                return R.data(null);
            }
        } else {
            try (InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(new File(filePath)))) {
//				okhttp3.OkHttpClient httpClient = new okhttp3.OkHttpClient();
//				Request requestUrl = new Request.Builder().url("file:///E:"+filePath).build();
//				Response response = httpClient.newCall(requestUrl).execute();
//				if (response.isSuccessful()) {
//					InputStream in = response.body().byteStream();
//					int size = in.available();
//					byte[] buffer = new byte[size];
//					in.read(buffer);
//					in.close();
//					str = new String(buffer,"UTF-8");
//				}
                //关闭输入输出流
//				InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(new File(filePath)));
                int len = 0;
                while ((len = inputStreamReader.read()) != -1) {
                    str = str + (char) len;
                }
            } catch (IOException e) {
                log.error("异常信息：{}", e);
                return R.data(null);
            }
        }

        return R.data(str);
    }


}
